#include "gn1640.h"
#include "modbus_user.h"

// 7段数码管字符编码表（共阴数码管，无小数点）
const SegCode_t SEG_CODE[] = {
    // 数字 0-9
    0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
    // 字母 A-Z
    0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x3D, 0x76, 0x30, 0x1E,
    0x00, 0x38, 0x00, 0x37, 0x3F, 0x73, 0x00, 0x00, 0x6D, 0x00,
    0x3E, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x5B,
    // 特殊字符     
    0x48, 0x40, 0x08, 0x00, 0x00
};

static SegCode_t g_displayData[16] = {0};
PosCtrl_t posCtrl;

SegCode_t *WritableList[8] = {0};
// 获取字符对应的7段数码管编码
SegCode_t GetAsciiCode(char c) 
{
    if (c >= '0' && c <= '9') {
        return SEG_CODE[c - '0'];
    }
    else if (c >= 'A' && c <= 'Z') {
        return SEG_CODE[10 + (c - 'A')]; // 字母从索引10开始
    }
    else if (c >= 'a' && c <= 'z') {
        return SEG_CODE[10 + (c - 'a')]; // 小写字母映射到大写
    }
    else {
        // 处理特殊字符
        switch(c) {
            case '=': return SEG_CODE[36];
            case '-': return SEG_CODE[37];
            case '_': return SEG_CODE[38];
            default: return SEG_CODE[40]; // 空格/未知字符/无法显示的字符
        }
    }
}

void PosCtrl_Init()
{
    posCtrl.num1     = &g_displayData[0];
    posCtrl.num2     = &g_displayData[1];
    posCtrl.unit1    = &g_displayData[2];
    posCtrl.num3     = &g_displayData[3];
    posCtrl.num4     = &g_displayData[4];
    posCtrl.unit2    = &g_displayData[5];
    posCtrl.top      = &g_displayData[8];
    posCtrl.bottom   = &g_displayData[7];
    posCtrl.display1 = &g_displayData[6];
    posCtrl.display2 = &g_displayData[9]; 

    WritableList[0] = posCtrl.num1;  
    WritableList[1] = posCtrl.num2;
    WritableList[2] = posCtrl.unit1;
    WritableList[3] = posCtrl.num3;
    WritableList[4] = posCtrl.num4;
    WritableList[5] = posCtrl.unit2;
    WritableList[6] = posCtrl.display1;
    WritableList[7] = posCtrl.display2;
}

void GN1640_Start() 
{
    GN1640_CLK = 1;
    GN1640_DATA = 1;
    T_CLK_LOW();
    GN1640_DATA = 0;
}

void GN1640_Stop() 
{
    GN1640_CLK = 1;
    GN1640_DATA = 0;
    T_CLK_HIGH();
    GN1640_DATA = 1;
}

// 发送单字节（LSB first）
void GN1640_WriteByte(uint8_t dat) 
{
    uint8_t i=0;
    for(; i<8; i++) 
    {
        GN1640_CLK = 0;
        GN1640_DATA = (dat >> i) & 0x01;
        T_HOLD();
        GN1640_CLK = 1;
        T_SETUP();
    }
}

// 设置地址模式（0:自增模式, 1:固定模式）
void GN1640_SetMode(uint8_t mode) 
{
    GN1640_Start();
    GN1640_WriteByte(0x40 | (mode ? 0x04 : 0x00)); // 指令头01XXXXXX
    GN1640_Stop();
}

// 设置显示地址（0xC0-0xCF）
void GN1640_SetAddress(uint8_t addr) 
{
    GN1640_Start();
    GN1640_WriteByte(0xC0 | (addr & 0x0F)); // 指令头11XXXXXX
    GN1640_Stop();
}

// 显示控制（亮度0-7级，enable:1开启/0关闭）
void GN1640_DisplayCtrl(uint8_t brightness, uint8_t enable) 
{
    GN1640_Start();
    GN1640_WriteByte(0x80 | (enable<<3) | (brightness & 0x07)); // 指令头10XXXXXX
    GN1640_Stop();
}

// 写入显示数据（自增模式）
void GN1640_WriteDataAuto(uint8_t *buff, uint8_t len) 
{
    uint8_t i = 0;
    GN1640_SetAddress(0xC0);  // 起始地址
    GN1640_Start();
    for( ;i<len; i++) 
        GN1640_WriteByte(buff[i]);   
    GN1640_Stop();
}
void GN1640_Refresh(void) 
{
    uint8_t i = 0;
    uint8_t zero[16] = {0};
    GN1640_WriteDataAuto(zero, 16);
    GN1640_SetAddress(0xC0);  // 起始地址
    GN1640_Start();
    for( ;i<16; i++) 
        GN1640_WriteByte(g_displayData[i]);   
    GN1640_Stop();
}
// 清空显示RAM（防上电乱码）
void GN1640_ClearRAM() 
{
    uint8_t zero[16] = {0};
    GN1640_WriteDataAuto(zero, 16);
    memset(g_displayData, 0, sizeof(g_displayData));
}

void DisplayNumber(uint8_t num, uint8_t pos) 
{
    g_displayData[pos] = SEG_CODE[num];  // 指定位置显示数字
    GN1640_Refresh();
}

void DisplayStr(char str, uint8_t pos) 
{
    g_displayData[pos] = GetAsciiCode(str); 
    GN1640_Refresh();
}

SegCode_t FindNumIndexFromSEG(uint8_t num)
{
    uint8_t i = 0;
    for(; i < 10; i++)
    {
        if(SEG_CODE[i] == num)
            return i;
    }
    return ERR_ITEM;     
}

void GN1640_Init() 
{
    int i = 0;
    P1_MODE_OUT_PP(GPIO_Pin_4);
    P1_MODE_OUT_PP(GPIO_Pin_5);
    // 1. 硬件初始化
    GN1640_CLK = 1;
    GN1640_DATA = 1;
    PosCtrl_Init();
    // 2. 设置地址自增模式
    GN1640_SetMode(0);
    // 3. 清空显示RAM
    GN1640_ClearRAM();
    // 4. 开启显示
    GN1640_DisplayCtrl(4, 1);

    *posCtrl.num1 = SEG_CODE[8];
    *posCtrl.num2 = SEG_CODE[8];
    *posCtrl.num3 = SEG_CODE[8];
    *posCtrl.num4 = SEG_CODE[8];
    *posCtrl.unit1 = SEG_CODE[8];
    *posCtrl.unit2 = SEG_CODE[8];
    *posCtrl.top   = SEG_CODE[8];
    *posCtrl.display1 = POS_POINT | POS_MINUS | POS_INFOR | POS_SYSTEM; 
    *posCtrl.display2 = POS_POINT | POS_MINUS | POS_INFOR | POS_SYSTEM;
    for ( i = 0; i < 7; i++)
    {
        *posCtrl.bottom |= 1 << i;
        GN1640_Refresh();
        delay_ms(120);
    }
    GN1640_Refresh();
    delay_ms(500);
    GN1640_ClearRAM();
    GN1640_Refresh();
}

/* pos 6 a:- b:小数 c:故障*/
